import { ipcMain } from "electron";
import { SerialPort, DelimiterParser, InterByteTimeoutParser } from "serialport";

const serials = new Map();

async function createSerial(mainWindow, option) {
  if (!option.baudRate) option.baudRate = 9600;
  if (!option.stopBits) option.stopBits = 1;
  if (!option.dataBits) option.dataBits = 8;
  if (!option.parity) option.parity = "none";
  // 清除已创建的串口，及其相关的ipc订阅
  const existSerial = serials.get(option.port);
  if (existSerial) {
    if (existSerial.isOpen) {
      return {
        error: true,
        msg: "串口使用中，无法重新创建"
      };
    }
    ipcMain.removeAllListeners(`serial-${option.port}-write`);
    ipcMain.removeAllListeners(`serial-${option.port}-open`);
    ipcMain.removeAllListeners(`serial-${option.port}-close`);
  }
  const serial = new SerialPort(
    {
      path: option.port,
      baudRate: option.baudRate,
      stopBits: option.stopBits,
      dataBits: option.dataBits,
      parity: option.parity,
      autoOpen: false
    },
    (err) => {
      if (err) mainWindow.webContents.send(`serial-${option.port}-error`, err.message);
    }
  );
  serials.set(option.port, serial);
  // 提供外部监听端口状态的IPC
  serial.on("open", () => mainWindow.webContents.send(`serial-${option.port}-status`, true));
  serial.on("close", () => mainWindow.webContents.send(`serial-${option.port}-status`, false));
  // 数据接收IPC，设置了分隔符的情况下通过分隔符进行接收完成的判定，否则通过间隔时间和最大接收字符判断
  if (option.delimiter) {
    const parser = serial.pipe(new DelimiterParser({ delimiter: option.delimiter }));
    parser.on("data", (d) => {
      mainWindow.webContents.send(`serial-${option.port}-read`, d);
      serial.flush();
    });
  } else {
    const parser = serial.pipe(new InterByteTimeoutParser({ interval: 200, maxBufferSize: 1024 }));
    parser.on("data", (d) => {
      mainWindow.webContents.send(`serial-${option.port}-read`, d);
      serial.flush();
    });
  }
  // 数据发送IPC
  ipcMain.on(`serial-${option.port}-write`, (_e, data) => {
    serial.write(Buffer.from(data));
  });
  // 异常监听IPC
  serial.on("error", (err) =>
    mainWindow.webContents.send(`serial-${option.port}-error`, err.message)
  );
  // 端口关闭及开启
  ipcMain.on(`serial-${option.port}-open`, () => {
    serial.open();
  });
  ipcMain.on(`serial-${option.port}-close`, () => {
    serial.close();
  });

  return option.port;
}

export function initSerialIpc(mainWindow) {
  ipcMain.handle("serial-list", async () => {
    return await SerialPort.list();
  });
  ipcMain.handle("create-serial", (_e, config) => createSerial(mainWindow, config));
}
